use actix_web::{get, middleware::Logger, post, web, App, HttpServer, Responder, Result};
use env_logger::Env;
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, sync::Mutex};
use actix_files as fs;
#[derive(Debug, Serialize, Deserialize)]
struct User {
    name: String,
    age: i32,
}

#[derive(Debug, Serialize)]
struct JsonResult {
    code: i32,
    msg: String,
    user: User,
}

#[derive(Debug)]
struct UserStore {
    //  多个线程修改需要使用Mutex, 参考:
    //  https://actix.rs/docs/application/
    users: Mutex<HashMap<String, i32>>,
}

#[get("/user/{name}")]
async fn get_user(name: web::Path<String>, state: web::Data<UserStore>) -> Result<impl Responder> {
    let name = name.into_inner();
    let users = state.users.lock().unwrap();
    let r = match users.get(&name) {
        Some(v) => JsonResult {
            code: 0,
            msg: format!("success found user {}", name),
            user: User {
                name: name,
                age: *v,
            },
        },
        None => JsonResult {
            code: -1,
            msg: format!("user {} not found", name),
            user: User {
                name: "".to_string(),
                age: -1,
            },
        },
    };

    Ok(web::Json(r))
}

#[post("/user")]
async fn add_user(u: web::Json<User>, state: web::Data<UserStore>) -> Result<impl Responder> {
    let mut users = state.users.lock().unwrap();
    users.insert(u.name.to_string(), u.age);
    let r = JsonResult {
        code: 0,
        msg: format!("add user {} age {} success", u.name, u.age),
        user: User {
            name: u.name.to_string(),
            age: u.age,
        },
    };
    println!("users is : {:?}", users);
    Ok(web::Json(r))
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    env_logger::init_from_env(Env::default().default_filter_or("info"));

    let users = web::Data::new(UserStore {
        users: Mutex::new(HashMap::new()),
    });

    HttpServer::new(move || {
        App::new()
            // 共享一个哈希表给所有路由，存储用户信息
            .app_data(users.clone())
            .wrap(Logger::default())
            .wrap(Logger::new("%a %s"))
            .service(fs::Files::new("/static", "./static").show_files_listing())
            .service(get_user)
            .service(add_user)
    })
        .bind(("localhost", 8001))?
        .run()
        .await
}

